import logging
import Queue
from ftplib import FTP
import os
import re
import time
import taskresult.base
import taskresult.parser  
from taskresult.mailsender import GenerateMailcontent, GenerateTaskFlowMailcontent, GenerateMailcontentNorespond, SendResultMail
import shutil
import threading
import task

ROOTPATH = 'taskresultpath'

class TaskFlowNodeInfo():
    '''
    Task flow node informaiton.
    '''
    def __init__(self, name, start_time, end_time, result, result_message, status):
        self.name = name
        self.start_time = start_time
        self.end_time = end_time
        self.result = result
        self.result_message = result_message
        self.status  = status


class TaskInfo():
    def __init__(self, name, templateid, taskid, subtasks, casesql, receiver):
        self.name = name
        self.templateid = templateid
        self.taskid = taskid
        self.subtasks = subtasks
        self.casesql = casesql
        self.receiver = receiver


class TaskFlowInfo():
    '''
    Task flow info.
    '''
    def __init__(self, name, templateid, taskid, result,
                  start_time, end_time, nodes_len, receiver, task_nodes):
        
        self.name = name
        self.templateid = templateid
        self.taskid = taskid
        self.receiver = receiver
        self.start_time = start_time
        self.end_time = end_time
        self.task_nodes = task_nodes
        self.nodes_len = nodes_len
        self.is_task_flow = True
        
        self.result = result
        self.message = ''
        
class NoRunSubTask():
    def __init__(self, start_time, end_time, result_message):
        self.id  = 0
        self.result = 3
        self.ip  = ''
        self.start_time = start_time
        self.end_time = end_time
        self.result_message = result_message

class Processor():
    def __init__(self, config):
        self.exits = False
        self.request = Queue.Queue()
        self.engine = None
        self.ftp = None
        self.config = config
        self.thread = None
    
    def Init(self):
        pass
    
    def Start(self):
        self.thread = threading.Thread(target=self.__Loop)
        self.thread.start()
        
    def Uninit(self):
        self.exits = True
        self.thread.join()
        logging.info('result process thread exits')
        
    def __Loop(self):
        while(not self.exits or not self.request.empty()):
            try:
                if self.request.empty():
                    time.sleep(0.2)
                    continue
                self.ftp = self.FTPInit()
                if self.ftp == None:
                    logging.warn('ftp connect fail')
                    time.sleep(1)
                    continue
                request = self.request.get()
                if isinstance(request, TaskFlowInfo):
                    self.AnalyTaskFlowResult(request)
                else:              
                    self.AnalyResult(request)
                self.ftp.close()
            except Exception as e:
                logging.exception(e)
                    
    
    def AnalyTaskFlowResult(self, info):
        '''
        Analy Task Flow Result
        '''
        mailcontent = GenerateTaskFlowMailcontent(info)
        SendResultMail(self.config.mail, info.receiver, info.name, mailcontent)
        
        
    def AnalyResult(self, info):    
        taskid = info.taskid
        casepath = os.path.join(ROOTPATH, "%d_%d" % (info.templateid, info.taskid))
        try:
            if os.path.exists(casepath):
                shutil.rmtree(casepath, True)
                os.mkdir(casepath)
        except OSError as e:
            logging.exception('create dir fial')
        result = None
        case_for_mail = []
        try:
            filelist, casefilelist, mail_content_list = self.DownloadResult(info.templateid, info.taskid)
            if info.casesql != None:
                result = self.engine.execute(info.casesql)
                needruncase = result.fetchall()
                cases = {}
                caselist = []
                for v in needruncase:
                    cases[v.Name] = v.Id
            
                    caselist = self.CaseResultParse(casefilelist)
                    
                for v in caselist:
                    if v.name in cases:
                        v.id = cases.pop(v.name)
                        case_for_mail.append(v)
                        self.resultinsert.execute(TaskId=taskid, CaseId=v.id,
                                                  ResultStatusId=v.result,
                                                  Message=v.message,
                                                  StartTime=v.start_time, EndTime=v.end_time)
        
                for v in cases:
                    ci = taskresult.base.CaseInfo()
                    ci.name = v
                    ci.result = taskresult.base.NORUN
                    case_for_mail.append(ci)
                    self.resultinsert.execute(TaskId=taskid, CaseId=cases[v], ResultStatusId=taskresult.base.NORUN)
                
            elif len(casefilelist) > 0:
                caselist = self.CaseResultParse(casefilelist)
                case_for_mail.extend(caselist)
            if info.receiver:
                mailcontent = GenerateMailcontent(info.name, info.subtasks, case_for_mail, filelist, mail_content_list)
                SendResultMail(self.config.mail, info.receiver, info.name, mailcontent)
        except Exception as e:
            logging.exception(e)
        finally:
            if result is not None:
                result.close
        logging.info('insert case result finish')
        
        
    def GetTaskFlowNodeInfo(self, node_info_list):
        '''
        Get task flow node information from DB(TestTask).
        '''
        node_list = []
        for v in node_info_list:
            node_info = TaskFlowNodeInfo(v.name,
                                        v.start_time,
                                        v.end_time,
                                        v.task_result,
                                        v.result_message, 
                                        v.status)
            node_list.append(node_info)
        return node_list
            
        
    def DownloadResult(self, templateid, taskid):    
        allfilelist = []  
        casefilelist = []
        mail_content_list = []
        filehandler = None
        try:
            taskpath = ("%d_%d" % (templateid, taskid))
            filelist = []
            
            self.GetFileInDir(filelist, taskpath)
        
            for v in filelist:
                p = os.path.join(ROOTPATH, os.path.dirname(v))
                if not os.path.exists(p):
                    os.makedirs(p)                
                name = os.path.join(ROOTPATH, v)
                filehandler = open(name, 'wb')
                self.ftp.retrbinary('RETR %s' % (v), filehandler.write)
                filehandler.close()
                filehandler = None
                allfilelist.append(name)
                if name.find('/case/') != -1:
                    casefilelist.append(name)
                if name.find('/mail/') != -1:
                    mail_content_list.append(name)
        except Exception:
            logging.exception('ftp download error')
        if filehandler:
            filehandler.close()
        return allfilelist, casefilelist, mail_content_list
    
    def FTPInit(self):
        ftp = FTP()
        try:
            ftp.connect(self.config.uploadcfg.ip, self.config.uploadcfg.port)
            ftp.login(self.config.uploadcfg.username, self.config.uploadcfg.password)
            ftp.getwelcome()
        except Exception as e:
            logging.exception(e)
            return None
        return ftp
    
    def GetFileInDir(self, filelist, path):
        fs = self.ftp.nlst(path)
        for v in fs:
            if v == path:
                name = unicode(v, 'utf-8').encode('gb2312')
                filelist.append(name)
            else:
                self.GetFileInDir(filelist, v)

    def CaseResultParse(self, filelist):
        resultlist = []
        for v in filelist:
            parsetype = re.findall(r'\((\w+)\)', os.path.basename(v))
            logging.info(parsetype)
            if parsetype :
                try:
                    parser = taskresult.parser.GetParser(parsetype[0])
                    result = parser(v)
                    resultlist.extend(result)
                except Exception:
                    logging.exception('parse test result fail')
            else:
                logging.warn('result filename not support')
        return resultlist
    
    
    def PutTaskResult(self, finish_task):
        
        mail_receiver = ""
        if finish_task.template.mailreciver != None and finish_task.template.mailreciver != "":
            mail_receiver = mail_receiver + ';' + finish_task.template.mailreciver
        
        if finish_task.result == task.SUCCESS:
            if finish_task.template.success_mail_receiver != "":
                mail_receiver = mail_receiver + ";" + finish_task.template.success_mail_receiver  
        elif finish_task.result == task.FAILURE:
            if finish_task.template.error_mail_receiver != "":
                mail_receiver = mail_receiver + ";" + finish_task.template.error_mail_receiver
        elif finish_task.result == task.EXCEPTION:
            if finish_task.template.error_mail_receiver != "":
                mail_receiver = mail_receiver + ";" + finish_task.template.except_mail_receiver
        
        if finish_task.addtional_mail_receiver != None and finish_task.addtional_mail_receiver != "" and finish_task.addtional_mail_receiver.find('@') >= 0:
            mail_receiver = mail_receiver + ';' + finish_task.addtional_mail_receiver
        
              
       
        if isinstance(finish_task, task.CaseTask):
            subtasks = finish_task.subtasks.values()
            if len(subtasks) == 0:
                subtasks = [NoRunSubTask(finish_task.begin_run_time, finish_task.end_time, finish_task.result_message)]
            ci = TaskInfo(finish_task.template.name,
                          finish_task.template.id,
                          finish_task.id,
                          subtasks,
                          finish_task.casesql,
                          mail_receiver)
        else:
            subtasks = finish_task.subtasks.values()
            if len(subtasks) == 0:
                subtasks = [NoRunSubTask(finish_task.begin_run_time, finish_task.end_time, finish_task.result_message)]
            ci = TaskInfo(finish_task.template.name,
                          finish_task.template.id,
                          finish_task.id,
                          subtasks,
                          None,
                          mail_receiver)
                        
        self.request.put(ci)
        
        
    def PutTaskFlowResult(self, task_flow):
        
        mail_receiver = ""
        if task_flow.template.mailreciver != None and task_flow.template.mailreciver != "":
            mail_receiver = mail_receiver + ';' + task_flow.template.mailreciver
        
        if task_flow.result == task.SUCCESS:
            if task_flow.template.success_mail_receiver != "":
                mail_receiver = mail_receiver + ";" + task_flow.template.success_mail_receiver  
        elif task_flow.result == task.FAILURE:
            if task_flow.template.error_mail_receiver != "":
                mail_receiver = mail_receiver + ";" + task_flow.template.error_mail_receiver
        elif task_flow.result == task.EXCEPTION:
            if task_flow.template.error_mail_receiver != "":
                mail_receiver = mail_receiver + ";" + task_flow.template.except_mail_receiver
        
        
        task_nodes = self.GetTaskFlowNodeInfo(task_flow.node_list.values())
        tfi = TaskFlowInfo(task_flow.template.name,
                          task_flow.template.id,
                          task_flow.dbid,
                          task_flow.result,
                          task_flow.begin_run_time,
                          task_flow.end_time,
                          len(task_flow.node_list),
                          mail_receiver,
                          task_nodes)
    
        self.request.put(tfi)




              
        
